/*! \file UnicodeConverter_unix.cpp
 *	\brief
 *
 *	created:	2010/08/08
 *	created:	8:8:2010   19:16
 *	filename: 	C:\Users\venn\Documents\projects\tactics-engine\libs\utils\unix\UnicodeConverter_unix.cpp
 *	file path:	C:\Users\venn\Documents\projects\tactics-engine\libs\utils
 *	file base:	UnicodeConverter
 *	file ext:	cpp
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */
#include "utils/stdafx.h"

#include <iconv.h>
#include <stdlib.h>

#include "utils/UnicodeConverter.h"

namespace tt{
namespace utils{

namespace impl{

class IconvDescriptor
{
public:
	IconvDescriptor(const char* tocode, const char* fromcode)
	{
		m_Descriptor = iconv_open(tocode, fromcode);
	}

	~IconvDescriptor()
	{
		iconv_close(m_Descriptor);
	}

	operator iconv_t() const
	{
		return m_Descriptor;
	}

private:
	iconv_t m_Descriptor;
};

iconv_t IconvDescriptor_FromAnsi()
{
	static IconvDescriptor s_descriptor("UTF-16", "CP-1251");
	return s_descriptor;
}

iconv_t IconvDescriptor_ToAnsi()
{
	static IconvDescriptor s_descriptor("CP-1251", "UTF-16");
	return s_descriptor;
}

iconv_t IconvDescriptor_FromUTF8()
{
	static IconvDescriptor s_descriptor("UTF-16", "UTF-8");
	return s_descriptor;
}

iconv_t IconvDescriptor_ToUTF8()
{
	static IconvDescriptor s_descriptor("UTF-8", "UTF-16");
	return s_descriptor;
}

/////////////////////////////////////////////////////////////////////////////////
template<typename SrcChar, typename DstChar>
Size count_template(iconv_t convertionDescription, const SrcChar* src, Size srcSize)
{
	const Size dstMaxSize = 8;
	Char dst[dstMaxSize] = {0};

	Char* srcPos = (Char*)src;
	Size srcLeft = srcSize;
    Char* dstPos = dst;
	Size dstLeft = dstMaxSize;

	Size dstSize = 0;
	for(;;)
	{
		size_t result = iconv(convertionDescription, &srcPos, &srcLeft, &dstPos, &dstLeft);
		if(result == -1)
			return -1;

		dstSize += dstMaxSize - dstLeft;

        dstPos = dst;
        dstLeft = dstMaxSize;

		if(srcLeft == 0)
			break;
	}
	return dstSize / sizeof(DstChar);
}

template<typename SrcChar, typename DstChar>
Size convertion_template(iconv_t convertionDescription, DstChar* dst, Size dstSize, const SrcChar* src, Size srcSize)
{
	Char* srcPos = (Char*)src;
	Size srcLeft = srcSize * sizeof(*srcPos);
	Char* dstPos = (Char*)dst;
	Size dstLeft = dstSize * sizeof(*dstPos);

	size_t result = iconv(convertionDescription, &srcPos, &srcLeft, &dstPos, &dstLeft);
	if(result == -1)
		return -1;
	return dstSize - dstLeft / sizeof(*dstPos);
}

/////////////////////////////////////////////////////////////////////////////////
Size from_ansi(CharW* dst, Size dstSize, const Char* src, Size srcSize)
{
	return convertion_template(IconvDescriptor_FromAnsi(), dst, dstSize, src, srcSize);
}

Size from_ansi_count(const Char* src, Size srcSize)
{
	return count_template<Char, CharW>( IconvDescriptor_FromAnsi(), src, srcSize );
}

Size to_ansi(Char* dst, Size dstSize, const CharW* src, Size srcSize)
{
	return convertion_template(IconvDescriptor_ToAnsi(), dst, dstSize, src, srcSize);
}

Size to_ansi_count(const CharW* src, Size srcSize)
{
	return count_template<CharW, Char>( IconvDescriptor_ToAnsi(), src, srcSize );
}

Size from_utf8(CharW* dst, Size dstSize, const Char* src, Size srcSize)
{
	return convertion_template(IconvDescriptor_FromUTF8(), dst, dstSize, src, srcSize);
}

Size from_utf8_count(const Char* src, Size srcSize)
{
	return count_template<Char, CharW>( IconvDescriptor_FromUTF8(), src, srcSize );
}

Size to_utf8(Char* dst, Size dstSize, const CharW* src, Size srcSize)
{
	return convertion_template(IconvDescriptor_ToUTF8(), dst, dstSize, src, srcSize);
}

Size to_utf8_count(const CharW* src, Size srcSize)
{
	return count_template<CharW, Char>( IconvDescriptor_ToUTF8(), src, srcSize );
}

} //namespace impl

} //namespace utils
} //namespace tt
